<!DOCTYPE html>
<html style="display: none;" lang="zh">
    <head><meta name="generator" content="Hexo 3.9.0">
    <!-- hexo-inject:begin --><!-- hexo-inject:end --><meta charset="utf-8">
    <!--
        © Material Theme
        https://github.com/viosey/hexo-theme-material
        Version: 1.5.2 -->
    <script>
        window.materialVersion = "1.5.2"
        // Delete localstorage with these tags
        window.oldVersion = [
            'codestartv1',
            '1.3.4',
            '1.4.0',
            '1.4.0b1',
            '1.5.0'
        ]
    </script>

    <!-- dns prefetch -->
    <meta http-equiv="x-dns-prefetch-control" content="on">














    <!-- Meta & Info -->
    <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
    <meta name="renderer" content="webkit">
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">

    <!-- Title -->
    
    <title>
        
            Ansible | 
        
        fengweizan&#39;s BLOG
    </title>

    <!-- Favicons -->
    <link rel="icon shortcut" type="image/ico" href="/img/favicon.png">
    <link rel="icon" href="/img/favicon.png">

    <meta name="format-detection" content="telephone=no">
    <meta name="description" itemprop="description" content="my blog with material design">
    <meta name="keywords" content=",devops">
    <meta name="theme-color" content="#0097A7">

    <!-- Disable Fucking Bloody Baidu Tranformation -->
    <meta http-equiv="Cache-Control" content="no-transform">
    <meta http-equiv="Cache-Control" content="no-siteapp">

    <!--[if lte IE 9]>
        <link rel="stylesheet" href="/css/ie-blocker.css">

        
            <script src="/js/ie-blocker.zhCN.js"></script>
        
    <![endif]-->

    <!-- Import lsloader -->
    <script>(function(){window.lsloader={jsRunSequence:[],jsnamemap:{},cssnamemap:{}};lsloader.removeLS=function(a){try{localStorage.removeItem(a)}catch(b){}};lsloader.setLS=function(a,c){try{localStorage.setItem(a,c)}catch(b){}};lsloader.getLS=function(a){var c="";try{c=localStorage.getItem(a)}catch(b){c=""}return c};versionString="/*"+(window.materialVersion||"unknownVersion")+"*/";lsloader.clean=function(){try{var b=[];for(var a=0;a<localStorage.length;a++){b.push(localStorage.key(a))}b.forEach(function(e){var f=lsloader.getLS(e);if(window.oldVersion){var d=window.oldVersion.reduce(function(g,h){return g||f.indexOf("/*"+h+"*/")!==-1},false);if(d){lsloader.removeLS(e)}}})}catch(c){}};lsloader.clean();lsloader.load=function(f,a,b,d){if(typeof b==="boolean"){d=b;b=undefined}d=d||false;b=b||function(){};var e;e=this.getLS(f);if(e&&e.indexOf(versionString)===-1){this.removeLS(f);this.requestResource(f,a,b,d);return}if(e){var c=e.split(versionString)[0];if(c!=a){console.log("reload:"+a);this.removeLS(f);this.requestResource(f,a,b,d);return}e=e.split(versionString)[1];if(d){this.jsRunSequence.push({name:f,code:e});this.runjs(a,f,e)}else{document.getElementById(f).appendChild(document.createTextNode(e));b()}}else{this.requestResource(f,a,b,d)}};lsloader.requestResource=function(b,e,a,c){var d=this;if(c){this.iojs(e,b,function(h,f,g){d.setLS(f,h+versionString+g);d.runjs(h,f,g)})}else{this.iocss(e,b,function(f){document.getElementById(b).appendChild(document.createTextNode(f));d.setLS(b,e+versionString+f)},a)}};lsloader.iojs=function(d,b,g){var a=this;a.jsRunSequence.push({name:b,code:""});try{var f=new XMLHttpRequest();f.open("get",d,true);f.onreadystatechange=function(){if(f.readyState==4){if((f.status>=200&&f.status<300)||f.status==304){if(f.response!=""){g(d,b,f.response);return}}a.jsfallback(d,b)}};f.send(null)}catch(c){a.jsfallback(d,b)}};lsloader.iocss=function(f,c,h,a){var b=this;try{var g=new XMLHttpRequest();g.open("get",f,true);g.onreadystatechange=function(){if(g.readyState==4){if((g.status>=200&&g.status<300)||g.status==304){if(g.response!=""){h(g.response);a();return}}b.cssfallback(f,c,a)}};g.send(null)}catch(d){b.cssfallback(f,c,a)}};lsloader.iofonts=function(f,c,h,a){var b=this;try{var g=new XMLHttpRequest();g.open("get",f,true);g.onreadystatechange=function(){if(g.readyState==4){if((g.status>=200&&g.status<300)||g.status==304){if(g.response!=""){h(g.response);a();return}}b.cssfallback(f,c,a)}};g.send(null)}catch(d){b.cssfallback(f,c,a)}};lsloader.runjs=function(f,c,e){if(!!c&&!!e){for(var b in this.jsRunSequence){if(this.jsRunSequence[b].name==c){this.jsRunSequence[b].code=e}}}if(!!this.jsRunSequence[0]&&!!this.jsRunSequence[0].code&&this.jsRunSequence[0].status!="failed"){var a=document.createElement("script");a.appendChild(document.createTextNode(this.jsRunSequence[0].code));a.type="text/javascript";document.getElementsByTagName("head")[0].appendChild(a);this.jsRunSequence.shift();if(this.jsRunSequence.length>0){this.runjs()}}else{if(!!this.jsRunSequence[0]&&this.jsRunSequence[0].status=="failed"){var d=this;var a=document.createElement("script");a.src=this.jsRunSequence[0].path;a.type="text/javascript";this.jsRunSequence[0].status="loading";a.onload=function(){d.jsRunSequence.shift();if(d.jsRunSequence.length>0){d.runjs()}};document.body.appendChild(a)}}};lsloader.tagLoad=function(b,a){this.jsRunSequence.push({name:a,code:"",path:b,status:"failed"});this.runjs()};lsloader.jsfallback=function(c,b){if(!!this.jsnamemap[b]){return}else{this.jsnamemap[b]=b}for(var a in this.jsRunSequence){if(this.jsRunSequence[a].name==b){this.jsRunSequence[a].code="";this.jsRunSequence[a].status="failed";this.jsRunSequence[a].path=c}}this.runjs()};lsloader.cssfallback=function(e,c,b){if(!!this.cssnamemap[c]){return}else{this.cssnamemap[c]=1}var d=document.createElement("link");d.type="text/css";d.href=e;d.rel="stylesheet";d.onload=d.onerror=b;var a=document.getElementsByTagName("script")[0];a.parentNode.insertBefore(d,a)};lsloader.runInlineScript=function(c,b){var a=document.getElementById(b).innerText;this.jsRunSequence.push({name:c,code:a});this.runjs()}})();</script>

    <!-- Import queue -->
    <script>function Queue(){this.dataStore=[];this.offer=b;this.poll=d;this.execNext=a;this.debug=false;this.startDebug=c;function b(e){if(this.debug){console.log("Offered a Queued Function.")}if(typeof e==="function"){this.dataStore.push(e)}else{console.log("You must offer a function.")}}function d(){if(this.debug){console.log("Polled a Queued Function.")}return this.dataStore.shift()}function a(){var e=this.poll();if(e!==undefined){if(this.debug){console.log("Run a Queued Function.")}e()}}function c(){this.debug=true}}var queue=new Queue();</script>

    <!-- Import CSS -->
    
        <style id="material_css"></style><script>if(typeof window.lsLoadCSSMaxNums === "undefined")window.lsLoadCSSMaxNums = 0;window.lsLoadCSSMaxNums++;lsloader.load("material_css","/css/material.min.css?Z7a72R1E4SxzBKR/WGctOA==",function(){if(typeof window.lsLoadCSSNums === "undefined")window.lsLoadCSSNums = 0;window.lsLoadCSSNums++;if(window.lsLoadCSSNums == window.lsLoadCSSMaxNums)document.documentElement.style.display="";}, false)</script>
        <style id="style_css"></style><script>if(typeof window.lsLoadCSSMaxNums === "undefined")window.lsLoadCSSMaxNums = 0;window.lsLoadCSSMaxNums++;lsloader.load("style_css","/css/style.min.css?MKetZV3cUTfDxvMffaOezg==",function(){if(typeof window.lsLoadCSSNums === "undefined")window.lsLoadCSSNums = 0;window.lsLoadCSSNums++;if(window.lsLoadCSSNums == window.lsLoadCSSMaxNums)document.documentElement.style.display="";}, false)</script>

        
            
                <style id="prettify_css"></style><script>if(typeof window.lsLoadCSSMaxNums === "undefined")window.lsLoadCSSMaxNums = 0;window.lsLoadCSSMaxNums++;lsloader.load("prettify_css","/css/prettify.min.css?zp8STOU9v89XWFEnN+6YmQ==",function(){if(typeof window.lsLoadCSSNums === "undefined")window.lsLoadCSSNums = 0;window.lsLoadCSSNums++;if(window.lsLoadCSSNums == window.lsLoadCSSMaxNums)document.documentElement.style.display="";}, false)</script>
                <style id="prettify_theme"></style><script>if(typeof window.lsLoadCSSMaxNums === "undefined")window.lsLoadCSSMaxNums = 0;window.lsLoadCSSMaxNums++;lsloader.load("prettify_theme","/css/prettify/github-v2.min.css?AfzKxt++K+/lhZBlSjnxwg==",function(){if(typeof window.lsLoadCSSNums === "undefined")window.lsLoadCSSNums = 0;window.lsLoadCSSNums++;if(window.lsLoadCSSNums == window.lsLoadCSSMaxNums)document.documentElement.style.display="";}, false)</script>
            
        

    

    

    <!-- Config CSS -->

<!-- Other Styles -->
<style>
  body, html {
    font-family: Roboto, "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
    overflow-x: hidden !important;
  }
  
  code {
    font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
  }

  a {
    color: #00838F;
  }

  .mdl-card__media,
  #search-label,
  #search-form-label:after,
  #scheme-Paradox .hot_tags-count,
  #scheme-Paradox .sidebar_archives-count,
  #scheme-Paradox .sidebar-colored .sidebar-header,
  #scheme-Paradox .sidebar-colored .sidebar-badge{
    background-color: #0097A7 !important;
  }

  /* Sidebar User Drop Down Menu Text Color */
  #scheme-Paradox .sidebar-colored .sidebar-nav>.dropdown>.dropdown-menu>li>a:hover,
  #scheme-Paradox .sidebar-colored .sidebar-nav>.dropdown>.dropdown-menu>li>a:focus {
    color: #0097A7 !important;
  }

  #post_entry-right-info,
  .sidebar-colored .sidebar-nav li:hover > a,
  .sidebar-colored .sidebar-nav li:hover > a i,
  .sidebar-colored .sidebar-nav li > a:hover,
  .sidebar-colored .sidebar-nav li > a:hover i,
  .sidebar-colored .sidebar-nav li > a:focus i,
  .sidebar-colored .sidebar-nav > .open > a,
  .sidebar-colored .sidebar-nav > .open > a:hover,
  .sidebar-colored .sidebar-nav > .open > a:focus,
  #ds-reset #ds-ctx .ds-ctx-entry .ds-ctx-head a {
    color: #0097A7 !important;
  }

  .toTop {
    background: #757575 !important;
  }

  .material-layout .material-post>.material-nav,
  .material-layout .material-index>.material-nav,
  .material-nav a {
    color: #757575;
  }

  #scheme-Paradox .MD-burger-layer {
    background-color: #757575;
  }

  #scheme-Paradox #post-toc-trigger-btn {
    color: #757575;
  }

  .post-toc a:hover {
    color: #00838F;
    text-decoration: underline;
  }

</style>


<!-- Theme Background Related-->

    <style>
      body {
        background-color: #F5F5F5;
      }

      /* blog_info bottom background */
      #scheme-Paradox .material-layout .something-else .mdl-card__supporting-text {
        background-color: #fff;
      }
    </style>




<!-- Fade Effect -->

    <style>
      .fade {
        transition: all 800ms linear;
        -webkit-transform: translate3d(0,0,0);
        -moz-transform: translate3d(0,0,0);
        -ms-transform: translate3d(0,0,0);
        -o-transform: translate3d(0,0,0);
        transform: translate3d(0,0,0);
        opacity: 1;
      }

      .fade.out{
        opacity: 0;
      }
    </style>


<!-- Import Font -->
<!-- Import Roboto -->

    <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet">


<!-- Import Material Icons -->


    <style id="material_icons"></style><script>if(typeof window.lsLoadCSSMaxNums === "undefined")window.lsLoadCSSMaxNums = 0;window.lsLoadCSSMaxNums++;lsloader.load("material_icons","/css/material-icons.css?pqhB/Rd/ab0H2+kZp0RDmw==",function(){if(typeof window.lsLoadCSSNums === "undefined")window.lsLoadCSSNums = 0;window.lsLoadCSSNums++;if(window.lsLoadCSSNums == window.lsLoadCSSMaxNums)document.documentElement.style.display="";}, false)</script>




    <!-- Import jQuery -->
    
        <script>lsloader.load("jq_js","/js/jquery.min.js?qcusAULNeBksqffqUM2+Ig==", true)</script>
    

    <!-- WebAPP Icons -->
    <meta name="mobile-web-app-capable" content="yes">
    <meta name="application-name" content="fengweizan&#39;s BLOG">
    <meta name="msapplication-starturl" content="https://fclehly.github.io/2019/06/01/Ansible/">
    <meta name="msapplication-navbutton-color" content="#0097A7">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-title" content="fengweizan&#39;s BLOG">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <link rel="apple-touch-icon" href="/img/favicon.png">

    <!-- Site Verification -->
    
    

    <!-- RSS -->
    

    <!-- The Open Graph protocol -->
    <meta property="og:url" content="https://fclehly.github.io/2019/06/01/Ansible/">
    <meta property="og:type" content="blog">
    <meta property="og:title" content="Ansible | fengweizan&#39;s BLOG">
    <meta property="og:image" content="/img/favicon.png">
    <meta property="og:description" content="my blog with material design">
    <meta property="og:article:tag" content="devops"> 

    
        <meta property="article:published_time" content="Sat Jun 01 2019 21:48:11 GMT+0800">
        <meta property="article:modified_time" content="Sat Jun 01 2019 21:57:28 GMT+0800">
    

    <!-- The Twitter Card protocol -->
    <meta name="twitter:card" content="summary_large_image">

    <!-- Add canonical link for SEO -->
    
        <link rel="canonical" href="https://fclehly.github.io/2019/06/01/Ansible/index.html">
    

    <!-- Structured-data for SEO -->
    
        


<script type="application/ld+json">
{
    "@context": "https://schema.org",
    "@type": "BlogPosting",
    "mainEntityOfPage": "https://fclehly.github.io/2019/06/01/Ansible/index.html",
    "headline": "Ansible",
    "datePublished": "Sat Jun 01 2019 21:48:11 GMT+0800",
    "dateModified": "Sat Jun 01 2019 21:57:28 GMT+0800",
    "author": {
        "@type": "Person",
        "name": "FWZ",
        "image": {
            "@type": "ImageObject",
            "url": "/img/avatar.png"
        },
        "description": "Hi, nice to meet you"
    },
    "publisher": {
        "@type": "Organization",
        "name": "fengweizan&#39;s BLOG",
        "logo": {
            "@type":"ImageObject",
            "url": "/img/favicon.png"
        }
    },
    "keywords": ",devops",
    "description": "my blog with material design",
}
</script>


    

    <!-- Analytics -->
    
    
    

    <!-- Custom Head --><!-- hexo-inject:begin --><!-- hexo-inject:end -->
    

</head>


    
        <body id="scheme-Paradox" class="lazy">
            <!-- hexo-inject:begin --><!-- hexo-inject:end --><div class="material-layout  mdl-js-layout has-drawer is-upgraded">
                

                <!-- Main Container -->
                <main class="material-layout__content" id="main">

                    <!-- Top Anchor -->
                    <div id="top"></div>

                    
                        <!-- Hamburger Button -->
                        <button class="MD-burger-icon sidebar-toggle">
                            <span class="MD-burger-layer"></span>
                        </button>
                    

                    <!-- Post TOC -->

    
    <!-- Back Button -->
    <!--
    <div class="material-back" id="backhome-div" tabindex="0">
        <a class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon"
           href="#" onclick="window.history.back();return false;"
           target="_self"
           role="button"
           data-upgraded=",MaterialButton,MaterialRipple">
            <i class="material-icons" role="presentation">arrow_back</i>
            <span class="mdl-button__ripple-container">
                <span class="mdl-ripple"></span>
            </span>
        </a>
    </div>
    -->


    <!-- Left aligned menu below button -->
    
    
    <button id="post-toc-trigger-btn"
        class="mdl-button mdl-js-button mdl-button--icon">
        <i class="material-icons">format_list_numbered</i>
    </button>

    <ul class="post-toc-wrap mdl-menu mdl-menu--bottom-left mdl-js-menu mdl-js-ripple-effect" for="post-toc-trigger-btn" style="max-height:80vh; overflow-y:scroll;">
        <ol class="post-toc"><li class="post-toc-item post-toc-level-1"><a class="post-toc-link" href="#ANSIBLE"><span class="post-toc-number">1.</span> <span class="post-toc-text">ANSIBLE</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#场景"><span class="post-toc-number">1.1.</span> <span class="post-toc-text">场景</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#常用自动化运维工具"><span class="post-toc-number">1.2.</span> <span class="post-toc-text">常用自动化运维工具</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#Ansible"><span class="post-toc-number">1.3.</span> <span class="post-toc-text">Ansible</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#特性"><span class="post-toc-number">1.3.1.</span> <span class="post-toc-text">特性</span></a></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#安装"><span class="post-toc-number">1.3.2.</span> <span class="post-toc-text">安装</span></a></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#组件"><span class="post-toc-number">1.3.3.</span> <span class="post-toc-text">组件</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#Inventory"><span class="post-toc-number">1.3.3.1.</span> <span class="post-toc-text">Inventory</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#AD-Hoc"><span class="post-toc-number">1.3.3.2.</span> <span class="post-toc-text">AD-Hoc</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#Playbook"><span class="post-toc-number">1.3.3.3.</span> <span class="post-toc-text">Playbook</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#Roles"><span class="post-toc-number">1.3.3.4.</span> <span class="post-toc-text">Roles</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#Galaxy"><span class="post-toc-number">1.3.3.5.</span> <span class="post-toc-text">Galaxy</span></a></li></ol></li></ol></li></ol></li></ol>
    </ul>
    




<!-- Layouts -->

    <!-- Post Module -->
    <div class="material-post_container">

        <div class="material-post mdl-grid">
            <div class="mdl-card mdl-shadow--4dp mdl-cell mdl-cell--12-col">

                <!-- Post Header(Thumbnail & Title) -->
                
    <!-- Paradox Post Header -->
    
        
            <!-- Random Thumbnail -->
            <div class="post_thumbnail-random mdl-card__media mdl-color-text--grey-50">
            <script type="text/ls-javascript" id="post-thumbnail-script">
    var randomNum = Math.floor(Math.random() * 19 + 1);

    $('.post_thumbnail-random').attr('data-original', '/img/random/material-' + randomNum + '.png');
    $('.post_thumbnail-random').addClass('lazy');
</script>

        
    
            <p class="article-headline-p">
                Ansible
            </p>
        </div>





                
                    <!-- Paradox Post Info -->
                    <div class="mdl-color-text--grey-700 mdl-card__supporting-text meta">

    <!-- Author Avatar -->
    <div id="author-avatar">
        <img src="/img/avatar.png" width="44px" height="44px" alt="Author Avatar"/>
    </div>
    <!-- Author Name & Date -->
    <div>
        <strong>FWZ</strong>
        <span>6月 01, 2019</span>
    </div>

    <div class="section-spacer"></div>

    <!-- Favorite -->
    <!--
        <button id="article-functions-like-button" class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon btn-like">
            <i class="material-icons" role="presentation">favorite</i>
            <span class="visuallyhidden">favorites</span>
        </button>
    -->

    <!-- Qrcode -->
    

    <!-- Tags (bookmark) -->
    
    <button id="article-functions-viewtags-button" class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon">
        <i class="material-icons" role="presentation">bookmark</i>
        <span class="visuallyhidden">bookmark</span>
    </button>
    <ul class="mdl-menu mdl-menu--bottom-right mdl-js-menu mdl-js-ripple-effect" for="article-functions-viewtags-button">
        <li class="mdl-menu__item">
        <a class="post_tag-link" href="/tags/devops/">devops</a>
    </ul>
    

    <!-- Share -->
    
        <button id="article-fuctions-share-button" class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon">
    <i class="material-icons" role="presentation">share</i>
    <span class="visuallyhidden">share</span>
</button>
<ul class="mdl-menu mdl-menu--bottom-right mdl-js-menu mdl-js-ripple-effect" for="article-fuctions-share-button">
    

    

    <!-- Share Weibo -->
    
        <a class="post_share-link" href="http://service.weibo.com/share/share.php?appkey=&title=Ansible&url=https://fclehly.github.io/2019/06/01/Ansible/index.html&pic=https://fclehly.github.io/img/favicon.png&searchPic=false&style=simple" target="_blank">
            <li class="mdl-menu__item">
                分享到微博
            </li>
        </a>
    

    <!-- Share Twitter -->
    
        <a class="post_share-link" href="https://twitter.com/intent/tweet?text=Ansible&url=https://fclehly.github.io/2019/06/01/Ansible/index.html&via=FWZ" target="_blank">
            <li class="mdl-menu__item">
                分享到 Twitter
            </li>
        </a>
    

    <!-- Share Facebook -->
    
        <a class="post_share-link" href="https://www.facebook.com/sharer/sharer.php?u=https://fclehly.github.io/2019/06/01/Ansible/index.html" target="_blank">
            <li class="mdl-menu__item">
                分享到 Facebook
            </li>
        </a>
    

    <!-- Share Google+ -->
    
        <a class="post_share-link" href="https://plus.google.com/share?url=https://fclehly.github.io/2019/06/01/Ansible/index.html" target="_blank">
            <li class="mdl-menu__item">
                分享到 Google+
            </li>
        </a>
    

    <!-- Share LinkedIn -->
    

    <!-- Share QQ -->
    

    <!-- Share Telegram -->
    
</ul>

    
</div>

                

                <!-- Post Content -->
                <div id="post-content" class="mdl-color-text--grey-700 mdl-card__supporting-text fade out">
    
        <h1 id="ANSIBLE"><a href="#ANSIBLE" class="headerlink" title="ANSIBLE"></a>ANSIBLE</h1><hr>
<p>[TOC]</p>
<hr>
<h2 id="场景"><a href="#场景" class="headerlink" title="场景"></a>场景</h2><p>为了操作远程主机，我们通常是ssh登录到对应的机子上并输入命令执行，安装软件、修改配置、等等。如果只有单台主机，这么做是完全OK的，顶多是把一些常用操作变成脚本减少重复操作。但是当有了两台主机甚至更多主机之后，同样的命令在另一台主机还要敲一遍，这样的操作就有点枯燥繁琐了。有的人觉得仅仅是多一台主机还好，那如果多10台主机呢，比如需求是在10台机子上配置redis集群，那么ssh登录到每台机子上进行操作是一件很sb的事。</p>
<p>一个简单的解决方案是：使用pssh。pssh可以通过ssh的方式批量发送命令到多台主机并执行，pscp可以批量拷贝文件到多台主机。但是pssh的缺点也很明显，就是功能太少。如果想要通过pssh进行复杂的操作，那就比较困难了。</p>
<p>多主机的配置管理是常见的场景，前人已经造好了轮子，也就是一些自动化运维工具，我们直接使用就行了。比较著名的也是国内用的最多的就是Ansible。</p>
<p>其实本质上Ansible或者说大部分运维工具主要解决以下自动化运维场景：</p>
<ul>
<li>文件传输</li>
<li>应用部署</li>
<li>配置管理</li>
<li>任务流编排</li>
</ul>
<h2 id="常用自动化运维工具"><a href="#常用自动化运维工具" class="headerlink" title="常用自动化运维工具"></a>常用自动化运维工具</h2><p>自动化运维工具主要可以分为两大类：</p>
<ol>
<li>需要装代理的；</li>
<li>不需要装代理的；</li>
</ol>
<p>第一种方式是指我们需要预先在目标主机上安装代理软件（在被控端上放个内鬼，就可以交易了），然后主控端通过通知代理软件来操纵被控端。</p>
<p>第二种方式是不需要在被控端安装代理软件，主要是通过ssh连接到被控主机进行控制操作，主控端需要提前得到被控主机的授权（比如秘钥对）才能进行相应的操作。</p>
<p>当前主流的自动化运维工具有：</p>
<ul>
<li>ansible：使用python编写，agentless，适用于中小型应用环境；</li>
<li>saltstack： 使用python编写，需要在每台机子上安装agent，执行效率更高；</li>
<li>puppet： 使用ruby编写，功能强大，配置复杂，重型，适合大型环境；</li>
<li>fabric：使用python编写，agentless，功能比较简单；</li>
</ul>
<p>由于puppet是使用ruby编写的，国内ruby玩家的数量远少于python，因此saltstack和ansible的使用者相对来说就比较多。fabric由于功能太少，完全能被ansible替代，所以企业用户很少使用fabric做复杂的任务流编排。</p>
<h2 id="Ansible"><a href="#Ansible" class="headerlink" title="Ansible"></a>Ansible</h2><h3 id="特性"><a href="#特性" class="headerlink" title="特性"></a>特性</h3><p>这里简单说一下ansible的主要特性：</p>
<ul>
<li>模块化：调用特定的模块，完成特定的任务，比如说rabbitmq模块特定用于部署rabbitmq，redis模块特定用户部署redis等；</li>
<li>有paramiko，pyyaml，jinja2三个关键模块，分别的功能是ssh连接并操作，解析yaml文件，jinjia2模板引擎；</li>
<li>支持自定义模块；</li>
<li>基于python实现；</li>
<li>部署简单，基于python和ssh，agentless；</li>
<li>安全，基于openssh；</li>
<li>支持playbook编排任务；</li>
<li>幂等性，第一次执行某个ansible的操作和第n次执行同样的ansible操作对主机状态的改变结果是一样的；</li>
<li>无需代理不依赖pki；</li>
<li>可使用任何语言写模块；</li>
<li>yaml格式，编排任务，支持丰富的数据结构；</li>
<li>较强大的多层解决方案；</li>
</ul>
<h3 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h3><p>只要用pip安装即可。</p>
<pre><code class="shell">&gt; pip install ansible
</code></pre>
<p>或者</p>
<pre><code>&gt; pip3 install ansible
</code></pre><p>完成。</p>
<p>配置文件主要在：</p>
<ol>
<li><code>/etc/ansible/ansible.cfg</code>，ansible工具本身的配置。</li>
<li><code>/etc/ansible/hosts</code>，静态主机清单（Inventory）配置。</li>
<li><code>/etc/ansible/roles/</code>，ansible-roles可以放在这。</li>
</ol>
<h3 id="组件"><a href="#组件" class="headerlink" title="组件"></a>组件</h3><h4 id="Inventory"><a href="#Inventory" class="headerlink" title="Inventory"></a>Inventory</h4><p>主机清单。对于批量主机操作，为了便捷的使用其中的部分主机，可以在inventory file中将其分组命名，默认的inventory file为<code>/etc/ansible/hosts</code>，inventory file可以有多个，且也可以通过Dynamic Inventory来动态生成。inventory文件的格式符合<code>INI</code>文件风格，中括号中的字符为组名。可以将同一个主机同时归并到多个不同的组中；如果目标主机使用非默认的SSH端口，还可以在主机名称之后使用冒号加端口号来表明。举个例子：</p>
<pre><code>[webserver]
172.1.1.40:2222
10.2.2.2
www.bbb.com

# 主机机名遵循相似的命名模式，还可使用列表的方式标识个主机
[mysqlserver]
db[01:10].dddd.com

[redisserver]
rds-[a:f].cloud.com

# 在inventory中定义主机时为其添加主机变量以便于在playbook中使用
[appserver]
10.3.3.3 maxMemoryUsage=60
10.4.4.4 servicePort=8099

# 定义指定组内所有主机上的在playbook中可用变量
[appsever:vars]
config-center=172.3.4.5
enable-water=true
</code></pre><h4 id="AD-Hoc"><a href="#AD-Hoc" class="headerlink" title="AD-Hoc"></a>AD-Hoc</h4><p>命令行模式使用ansible。</p>
<p>使用<code>ansible --help</code>可查看如何使用</p>
<pre><code class="shell">fwz@fwz-mbp ~/Workspace&gt; ansible --help
Usage: ansible &lt;host-pattern&gt; [options]

Define and run a single task &#39;playbook&#39; against a set of hosts

Options:
  -a MODULE_ARGS, --args=MODULE_ARGS
                        module arguments
  --ask-vault-pass      ask for vault password
  -B SECONDS, --background=SECONDS
                        run asynchronously, failing after X seconds
                        (default=N/A)
  -C, --check           don&#39;t make any changes; instead, try to predict some
                        of the changes that may occur
  -D, --diff            when changing (small) files and templates, show the
                        differences in those files; works great with --check
......
......
</code></pre>
<p>简单的说，语法就是<code>ansible &lt;host-pattern&gt; [-f forks] [-m module_name] [-a args]</code></p>
<p>本质上，就是调用相应的ansible模块，并传入相应的参数。</p>
<p>举几个例子:</p>
<p>ping所有主机（使用ping模块）：</p>
<pre><code class="shell">&gt; ansible all -a ping --ask-pass
ansible all -m ping --ask-pass
SSH password:
xx.xx.xx.xxx | SUCCESS =&gt; {
    &quot;changed&quot;: false,
    &quot;ping&quot;: &quot;pong&quot;
}
</code></pre>
<p>改变文件属性（使用file模块）:</p>
<pre><code class="shell">&gt; ansible mysql-server -m file -a &#39;owner=mysql group=mysql mode=644 path=/tmp/fstab.ansible&#39;
</code></pre>
<p>拷贝文件（使用copy模块）:</p>
<pre><code class="shell">&gt; ansible storageIndex-server -m copy -a &#39;src=/home/devops/cloud-relay-1.2.4-SNAPSHOT.tar.gz dest=/root/cloud-storageIndex/cloud-relay-1.2.4.tar.gz&#39;
</code></pre>
<p>配置Rabbitmq（使用rabbitmq_user模块）:</p>
<pre><code class="shell">&gt; ansible rabbitmq-server -m rabbitmq_user -a &#39;user=new_user password=root tags=administrator vhost=/ state=present&#39;
</code></pre>
<p>执行linux的命令（使用shell模块）：</p>
<pre><code class="shell">&gt; ansible webserver -m shell -a &#39;netstat -nutlp &gt; netstat_temp.txt&#39;
</code></pre>
<h4 id="Playbook"><a href="#Playbook" class="headerlink" title="Playbook"></a>Playbook</h4><p>剧本。虽然可以在命令行中使用ansible，但是明显功能有限，无法支持复杂环境的配置管理工作。首先，命令行一次只能执行一条命令，其次，由于通常是手敲命令，因此不好重复。类似于linux中的shell脚本，ansible提供了playbook，翻译为剧本，用于组织基于多个ansible模块交互的工作流编排。</p>
<p>linux的脚本文件是<code>.sh</code>文件，ansible-playbook则是<code>.yaml</code>文件，即使用YAML语法。YAML的语法和其他高阶语言类似，并且可以简单表达清单、散列表、标量等数据结构。</p>
<p>直接举个例子：</p>
<pre><code class="yaml">---
# This playbook will install mysql and create db user and give permissions.
- hosts: $servername
  remote_user: root
  - name: Install Mysql package
    yum: name={{ item }} state=installed
    with_items:
     - mysql-server
     - MySQL-python
     - libselinux-python
     - libsemanage-python

  - name: Configure SELinux to start mysql on any port
    seboolean: name=mysql_connect_any state=true persistent=yes
    when: sestatus.rc != 0

  - name: Create Mysql configuration file
    template: src=my.cnf.j2 dest=/etc/my.cnf
    notify:
    - restart mysql

  - name: Start Mysql Service
    service: name=mysqld state=started enabled=yes

  - name: insert iptables rule
    lineinfile: dest=/etc/sysconfig/iptables state=present regexp=&quot;{{ mysql_port }}&quot;
                insertafter=&quot;^:OUTPUT &quot; line=&quot;-A INPUT -p tcp  --dport {{ mysql_port }} -j  ACCEPT&quot;
    notify: restart iptables

  - name: Create Application Database
    mysql_db: name={{ dbname }} state=present

  - name: Create Application DB User
    mysql_user: name={{ dbuser }} password={{ upassword }} priv=*.*:ALL host=&#39;%&#39; state=present
</code></pre>
<p>例子很好理解，首先是定义了这个playbook在哪个主机组中执行，以及对应的用户，接着是一组task，分别调用了yum、seboolean、template、service、lineinfile、mysql_db、mysql_user模块。其中使用了notify作handler。</p>
<p>hosts：playbook中的每一个play的目的都是为了让某个或某些主机以某个指定的用户身份执行任务。hosts用于指定要执行指定任务的主机，其可以使一个或多个由冒号分隔主机组；</p>
<p>remote_user: remote_user也可用于各task中，也可以通过指定其通过sudo的方式在远程主机上执行任务，其可用于play全局或其任务；此外，甚至可以在sudo时使用sudo_user指定sudo时切换的用户。</p>
<p>task：play的主题部分是task list。task list中的各任务按次序逐个在hosts中指定的所有主机上执行，即在所有主机上完成第一个任务后再开始第二个。在运行自上而下某playbook时，如果中途发生错误，所有已执行任务都可能回滚，在更正playbook后重新执行一次即可。</p>
<p>taks的目的是使用指定的参数执行模块，而在模块参数中可以使用变量。模块执行是幂等的。这意味着多次执行是安全的，因为其结果均一致。</p>
<p>每个task都应该有其name，用于playbook的执行结果输出，建议其内容尽可能清晰地描述任务执行步骤，如果为提供name，则action的结果将用于输出。</p>
<p>定义task可以使用”action: module options”或”module：options“的格式推荐使用后者以实现向后兼容。如果action一行的内容过多，也中使用在行首使用几个空白字符进行换行。</p>
<pre><code class="yaml">tasks:
 - name:make sure apache is running
   service: name=httpd state=started
</code></pre>
<p>在众多的模块中，只有command和shell模块仅需要给定一个列表而无需使用”key=value”格式</p>
<pre><code class="yaml">tasks:
 - name: run this command and ignore the result
   shell: /usr/bin/somecommand || /bin/true
</code></pre>
<p>Handler: 用于当关注的资源发生变化时采取一定的操作。</p>
<p>“notify”这个action可用于在每个play的最后被触发，这样可以避免多次有改变发生时每次都执行执行的操作，取而代之，仅在所有的变化发生完成后一次性地执行指定操作，在notify中列出的操作称为handlers，也即notify中调用handlers中定义的操作。</p>
<pre><code class="yaml">- name: template configuration file
 template: src=template.j2 dest=/etc/foo.conf
 notify:
   - restart memcached
   - restart apache
</code></pre>
<h4 id="Roles"><a href="#Roles" class="headerlink" title="Roles"></a>Roles</h4><p>ansible自1.2版本引入的新特性，用于层次性、结构化地组织playbook。roles能够根据层次型结构自动转载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单来讲，roles就是通过分别将变量、文件、任务、模板以及处理器放置于单独的目录中，并可以便捷地include他们的一种机制。角色一般用于基于主机构建服务的场景中，但也可以使用于构建守护进程的场景中。</p>
<p>一个常用的role结构：</p>
<pre><code class="shell">site.yml
webserver.yml
fooserver.yml
roles/
   common/
       files/
       templates/
       tasks/
       handlers/
       vars/
       meta/
   webserver/
       files/
       templates/
       tasks/
       handlers/
       vars/
       meta/
</code></pre>
<p>在ansible-playbook中可以这么使用role：</p>
<pre><code class="yaml">- hosts: webserver
 roles:
   - common  
   - webserver
</code></pre>
<p>向role中传递参数：</p>
<pre><code class="yaml">- hosts: webserver
 roles:
   - common
   - { role: foo_app_instance, dir:&#39;/opt/a&#39;,port:5000}
   - { role: foo_app_instance, dir:&#39;/opt/b&#39;,port:5001}
</code></pre>
<ul>
<li>task目录：至少应该包含一个为main.yml的文件，其定义了此角色的任务列表；此文件可以使用include包含其它的位于此目录中的task文件；</li>
<li>file目录：存放由copy或script等模板块调用的文件；</li>
<li>template目录：template模块会自动在此目录中寻找jinja2模板文件；</li>
<li>handlers目录：此目录中应当包含一个main.yml文件，用于定义此角色用到的各handlers，在handler中使用inclnude包含的其它的handlers文件也应该位于此目录中；</li>
<li>vars目录：应当包含一个main.yml文件，用于定义此角色用到的变量</li>
<li>meta目录：应当包含一个main.yml文件，用于定义此角色的特殊设定及其依赖关系；ansible1.3及其以后的版本才支持；</li>
<li>default目录：应当包含一个main.yml文件,用于为当前角色设定默认变量时使用此目录；</li>
</ul>
<p>官方提供了很多ansible-roles的例子：<a href="https://github.com/ansible">ansible/<strong>ansible-examples</strong></a></p>
<h4 id="Galaxy"><a href="#Galaxy" class="headerlink" title="Galaxy"></a>Galaxy</h4><p>用于分享和下载ansible-role的平台，类似于同性交友网站github。</p>

        
    

    
</div>


                

                <!-- Post Comments -->
                
                    
                
            </div>

            <!-- Post Prev & Next Nav -->
            <nav class="material-nav mdl-color-text--grey-50 mdl-cell mdl-cell--12-col">
    <!-- Prev Nav -->
    
        <a href="/2019/06/18/Config-Center-Apollo/" id="post_nav-newer" class="prev-content">
            <button class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon mdl-color--white mdl-color-text--grey-900" role="presentation">
                <i class="material-icons">arrow_back</i>
            </button>
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
            新篇
        </a>
    

    <!-- Section Spacer -->
    <div class="section-spacer"></div>

    <!-- Next Nav -->
    
        <a href="/2019/01/01/Points-on-Serverless/" id="post_nav-older" class="next-content">
            旧篇
            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
            <button class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon mdl-color--white mdl-color-text--grey-900" role="presentation">
                <i class="material-icons">arrow_forward</i>
            </button>
        </a>
    
</nav>

        </div>
    </div>



                    
                        <!-- Overlay For Active Sidebar -->
<div class="sidebar-overlay"></div>

<!-- Material sidebar -->
<aside id="sidebar" class="sidebar sidebar-colored sidebar-fixed-left" role="navigation">
    <div id="sidebar-main">
        <!-- Sidebar Header -->
        <div class="sidebar-header header-cover" style="background-image: url(/img/sidebar_header.png);">
    <!-- Top bar -->
    <div class="top-bar"></div>

    <!-- Sidebar toggle button -->
    <button type="button" class="sidebar-toggle mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon" style="display: initial;" data-upgraded=",MaterialButton,MaterialRipple">
        <i class="material-icons">clear_all</i>
        <span class="mdl-button__ripple-container">
            <span class="mdl-ripple">
            </span>
        </span>
    </button>

    <!-- Sidebar Avatar -->
    <div class="sidebar-image">
        <img src="/img/avatar.png" alt="FWZ's avatar">
    </div>

    <!-- Sidebar Email -->
    <a data-toggle="dropdown" class="sidebar-brand" href="#settings-dropdown">
        youremail@email.com
        <b class="caret"></b>
    </a>
</div>


        <!-- Sidebar Navigation  -->
        <ul class="nav sidebar-nav">
    <!-- User dropdown  -->
    <li class="dropdown">
        <ul id="settings-dropdown" class="dropdown-menu">
            
                <li>
                    <a href="#" target="_blank" title="Email Me">
                        
                            <i class="material-icons sidebar-material-icons sidebar-indent-left1pc-element">email</i>
                        
                        Email Me
                    </a>
                </li>
            
        </ul>
    </li>

    <!-- Homepage -->
    
        <li id="sidebar-first-li">
            <a href="/">
                
                    <i class="material-icons sidebar-material-icons">home</i>
                
                主页
            </a>
        </li>
        
    

    <!-- Archives  -->
    
        <li class="dropdown">
            <a href="#" class="ripple-effect dropdown-toggle" data-toggle="dropdown">
                
                    <i class="material-icons sidebar-material-icons">inbox</i>
                
                    归档
                <b class="caret"></b>
            </a>
            <ul class="dropdown-menu">
            <li>
                <a class="sidebar_archives-link" href="/archives/2019/09/">九月 2019<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/archives/2019/08/">八月 2019<span class="sidebar_archives-count">3</span></a></li><li><a class="sidebar_archives-link" href="/archives/2019/07/">七月 2019<span class="sidebar_archives-count">7</span></a></li><li><a class="sidebar_archives-link" href="/archives/2019/06/">六月 2019<span class="sidebar_archives-count">3</span></a></li><li><a class="sidebar_archives-link" href="/archives/2019/01/">一月 2019<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/archives/2018/12/">十二月 2018<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/archives/2018/07/">七月 2018<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/archives/2018/06/">六月 2018<span class="sidebar_archives-count">2</span></a></li><li><a class="sidebar_archives-link" href="/archives/2018/05/">五月 2018<span class="sidebar_archives-count">3</span></a>
            </ul>
        </li>
        
    

    <!-- Categories  -->
    

    <!-- Pages  -->
    

    <!-- Article Number  -->
    
</ul>


        <!-- Sidebar Footer -->
        <!--
I'm glad you use this theme, the development is no so easy, I hope you can keep the copyright, I will thank you so much.
If you still want to delete the copyrights, could you still retain the first one? Which namely "Theme Material"
It will not impact the appearance and can give developers a lot of support :)

很高兴您使用并喜欢该主题，开发不易 十分谢谢与希望您可以保留一下版权声明。
如果您仍然想删除的话 能否只保留第一项呢？即 "Theme Material"
它不会影响美观并可以给开发者很大的支持和动力。 :)
-->

<!-- Sidebar Divider -->

    <div class="sidebar-divider"></div>


<!-- Theme Material -->

    <a href="https://github.com/viosey/hexo-theme-material"  class="sidebar-footer-text-a" target="_blank">
        <div class="sidebar-text mdl-button mdl-js-button mdl-js-ripple-effect sidebar-footer-text-div" data-upgraded=",MaterialButton,MaterialRipple">
            主题 - Material
            <span class="sidebar-badge badge-circle">i</span>
        </div>
    </a>


<!-- Help & Support -->
<!--

-->

<!-- Feedback -->
<!--

-->

<!-- About Theme -->
<!--

-->

    </div>

    <!-- Sidebar Image -->
    

</aside>

                    

                    
                        <!-- Footer Top Button -->
                        <div id="back-to-top" class="toTop-wrap">
    <a href="#top" class="toTop">
        <i class="material-icons footer_top-i">expand_less</i>
    </a>
</div>

                    

                    <!--Footer-->
<footer class="mdl-mini-footer" id="bottom">
    
    <!-- Paradox Footer Left Section -->
    <div class="mdl-mini-footer--left-section sns-list">
    <!-- Twitter -->
    
        <a href="https://twitter.com/twitter" target="_blank">
            <button class="mdl-mini-footer--social-btn social-btn footer-sns-twitter">
                <span class="visuallyhidden">Twitter</span>
            </button><!--
     --></a>
    

    <!-- Facebook -->
    
        <a href="https://www.facebook.com/facebook" target="_blank">
            <button class="mdl-mini-footer--social-btn social-btn footer-sns-facebook">
                <span class="visuallyhidden">Facebook</span>
            </button><!--
     --></a>
    

    <!-- Google + -->
    
        <a href="https://www.google.com/" target="_blank">
            <button class="mdl-mini-footer--social-btn social-btn footer-sns-gplus">
                <span class="visuallyhidden">Google Plus</span>
            </button><!--
     --></a>
    

    <!-- Weibo -->
    

    <!-- Instagram -->
    

    <!-- Tumblr -->
    

    <!-- Github -->
    

    <!-- LinkedIn -->
    

    <!-- Zhihu -->
    

    <!-- Bilibili -->
    

    <!-- Telegram -->
    
    
    <!-- V2EX -->
    
</div>


    <!--Copyright-->
    <div id="copyright">
        Copyright&nbsp;©
        <script
            type="text/javascript">var fd = new Date(); document.write("&nbsp;" + fd.getFullYear() + "&nbsp;");</script>
        fengweizan's BLOG
        
    </div>

    <!-- Paradox Footer Right Section -->

    <!--
        I am glad you use this theme, the development is no so easy, I hope you can keep the copyright.
        It will not impact the appearance and can give developers a lot of support :)

        很高兴您使用该主题，开发不易，希望您可以保留一下版权声明。
        它不会影响美观并可以给开发者很大的支持。 :)
        -->

    <div class="mdl-mini-footer--right-section">
        <div>
            <div class="footer-develop-div">Powered by <a href="https://hexo.io" target="_blank"
                    class="footer-develop-a">Hexo</a></div>
            <div class="footer-develop-div">Theme - <a href="https://github.com/viosey/hexo-theme-material"
                    target="_blank" class="footer-develop-a">Material</a></div>
        </div>
    </div>
    
</footer>



                    <!-- Import JS File -->

    <script>lsloader.load("lazyload_js","/js/lazyload.min.js?1BcfzuNXqV+ntF6gq+5X3Q==", true)</script>



    <script>lsloader.load("js_js","/js/js.min.js?V/53wGualMuiPM3xoetD5Q==", true)</script>



    <script>lsloader.load("np_js","/js/nprogress.js?pl3Qhb9lvqR1FlyLUna1Yw==", true)</script>


<script type="text/ls-javascript" id="NProgress-script">
    NProgress.configure({
        showSpinner: true
    });
    NProgress.start();
    $('#nprogress .bar').css({
        'background': '#29d'
    });
    $('#nprogress .peg').css({
        'box-shadow': '0 0 10px #29d, 0 0 15px #29d'
    });
    $('#nprogress .spinner-icon').css({
        'border-top-color': '#29d',
        'border-left-color': '#29d'
    });
    setTimeout(function() {
        NProgress.done();
        $('.fade').removeClass('out');
    }, 800);
</script>













<!-- UC Browser Compatible -->
<script>
	var agent = navigator.userAgent.toLowerCase();
	if(agent.indexOf('ucbrowser')>0) {
		document.write('<link rel="stylesheet" href="/css/uc.css">');
	   alert('由于 UC 浏览器使用极旧的内核，而本网站使用了一些新的特性。\n为了您能更好的浏览，推荐使用 Chrome 或 Firefox 浏览器。');
	}
</script>

<!-- Import prettify js  -->

    
        
            <script>lsloader.load("prettify_js","/js/prettify.min.js?WN07fivHQSMKWy7BmHBB6w==", true)</script>
        
    



<!-- Window Load -->
<!-- add class for prettify -->
<script type="text/ls-javascript" id="window-load">
    $(window).on('load', function() {
        // Post_Toc parent position fixed
        $('.post-toc-wrap').parent('.mdl-menu__container').css('position', 'fixed');
    });

    
        
            $(function() {
                $('pre').addClass('prettyprint linenums').attr('style', 'overflow:auto;');
                prettyPrint();
                })
        
    
    
</script>

<!-- MathJax Load-->


<!-- Bing Background -->

<script type="text/ls-javascript" id="Bing-Background-script">
    queue.offer(function(){
        $('body').attr('data-original', 'https://api.i-meto.com/bing?');
    });
</script>


<script type="text/ls-javascript" id="lazy-load">
    // Offer LazyLoad
    queue.offer(function(){
        $('.lazy').lazyload({
            effect : 'show'
        });
    });

    // Start Queue
    $(document).ready(function(){
        setInterval(function(){
            queue.execNext();
        },200);
    });
</script>

<!-- Custom Footer -->



<script>
    (function(){
        var scriptList = document.querySelectorAll('script[type="text/ls-javascript"]')

        for (var i = 0; i < scriptList.length; ++i) {
            var item = scriptList[i];
            lsloader.runInlineScript(item.id,item.id);
        }
    })()
console.log('\n %c © Material Theme | Version: 1.5.2 | https://github.com/viosey/hexo-theme-material %c \n', 'color:#455a64;background:#e0e0e0;padding:5px 0;border-top-left-radius:5px;border-bottom-left-radius:5px;', 'color:#455a64;background:#e0e0e0;padding:5px 0;border-top-right-radius:5px;border-bottom-right-radius:5px;');
</script>

                </main>
            </div><!-- hexo-inject:begin --><!-- hexo-inject:end -->
        </body>
    
</html>
